package com.example.flow.flow.core;

import com.example.flow.dao.model.FlowOrder;
import com.example.flow.dao.model.FlowProcess;
import com.example.flow.dao.model.FlowTask;
import com.example.flow.flow.model.NodeModel;
import com.example.flow.flow.model.ProcessModel;
import com.example.flow.flow.model.StartModel;
import com.example.flow.flow.model.TransitionModel;
import com.example.flow.flow.service.FlowOrderService;
import com.example.flow.flow.service.FlowProcessService;
import com.example.flow.flow.service.FlowTaskService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;

/**
 * @author tangaq
 * 2023/6/13
 */
@Component
public class FlowEngine {
    private static final Logger log = LoggerFactory.getLogger(FlowEngine.class);
    private final FlowProcessService flowProcessService;
    private final FlowOrderService flowOrderService;
    private final FlowTaskService flowTaskService;

    public FlowEngine(FlowProcessService flowProcessService,
                      FlowOrderService flowOrderService,
                      FlowTaskService flowTaskService) {
        this.flowProcessService = flowProcessService;
        this.flowOrderService = flowOrderService;
        this.flowTaskService = flowTaskService;
    }

    public FlowProcessService getProcessService() {
        return flowProcessService;
    }

    public FlowOrderService getOrderService() {
        return flowOrderService;
    }

    public FlowTaskService getTaskService() {
        return flowTaskService;
    }

    /**
     * 创建流程实例 并返回执行对象
     *
     * @param process 流程定义
     * @param args    流程参数
     * @return
     */
    private Execution execute(FlowProcess process, Map<String, Object> args) {
        FlowOrder order = flowOrderService.createOrder(process, args);
        return new Execution(this, process, order, args);
    }

    /**
     * 通过流程模板编号启动流程
     * 适用于执行历史流程模板
     */
    @Transactional(rollbackFor = Exception.class)
    public FlowOrder startInstanceById(String processId, Map<String, Object> args) {
        log.info("流程平台收到,processId:{}，发起流程", processId);
        FlowProcess process = flowProcessService.findByProcessId(processId);
        return startProcess(process, args);
    }

    /**
     * 需求要求编辑后的流程要按照之前的模板要继续流转
     * 优先使用通过processId启动
     */
    @Transactional(rollbackFor = Exception.class)
    public FlowOrder startInstanceByType(String processType, Map<String, Object> args) {
        FlowProcess process = flowProcessService.findLatestByProcessType(processType);
        return startProcess(process, args);
    }

    private FlowOrder startProcess(FlowProcess process, Map<String, Object> args) {
        Execution execute = this.execute(process, args);
        if (process.getModel() != null) {
            StartModel start = process.getModel().getStart();
            start.execute(execute);
        }
        return execute.getOrder();
    }

    /**
     * 执行任务
     */
    @Transactional(rollbackFor = Exception.class)
    public FlowTask executeTask(String taskId, Map<String, Object> args) {
        Execution execution = this.execute(taskId, args);
        ProcessModel model = execution.getProcess().getModel();
        if (model != null) {
            NodeModel nodeModel = model.getNode(execution.getTask().getTaskName());
            //将执行对象交给该任务对应的节点模型执行
            nodeModel.execute(execution);
        }
        return execution.getTask();
    }

    private Execution execute(String taskId, Map<String, Object> args) {
        if (args == null) args = new HashMap<>();
        FlowTask task = flowTaskService.complete(taskId);
        FlowOrder order = flowOrderService.findByOrderId(task.getOrderId());
        FlowProcess process = flowProcessService.findByProcessId(order.getProcessId());
        Execution execution = new Execution(this, process, order, args);
        execution.setTask(task);
        return execution;
    }

    /**
     * 跳转任意节点
     * 1.nodeName为null 驳回上一节点
     * 2.nodeName不为null 任意跳转
     */
    public FlowTask executeAndJump(String taskId, Map<String, Object> args, String nodeName) {
        Execution execution = execute(taskId, args);
        ProcessModel model = execution.getProcess().getModel();
        if (StringUtils.isEmpty(nodeName)) {
            FlowTask newTask = flowTaskService.rejectTask(model, execution.getTask());
            execution.setTask(newTask);
        } else {
            NodeModel nodeModel = model.getNode(nodeName);

            //动态创建转移对象，由转移对象执行execution实例
            TransitionModel tm = new TransitionModel();
            tm.setTarget(nodeModel);
            tm.execute(execution);
        }
        return execution.getTask();
    }

    public void deleteByOrderId(String orderId) {
        if (StringUtils.isBlank(orderId)) {
            return;
        }
        flowOrderService.deleteByOrderId(orderId);
        flowTaskService.deleteByOrderId(orderId);
    }
}
